﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using XnaDevRu.ContentBuilder.Framework;
using System.IO;
using System.Xml;

namespace TestContentBuilder
{
    public partial class mainForm : Form
    {
        private string _projectName = "Unnamed";
        private ContentProject _project;
        private string[] _acceptableFileFormat = { ".x", ".fbx", ".tga", ".jpg", ".dds" };

        static System.Windows.Forms.OpenFileDialog StaticOpenFileDialog = null;

        static mainForm StaticMainForm = null;

        public class ProjectPropertiesDesc
        {
            public class AssemblyInfo
            {
                private string _fileName;
                [DisplayName("Filename")]
                [Description("Assembly filename")]
                public string FileName
                {
                    get { return _fileName; }
                    set { _fileName = value; }
                }

                public AssemblyInfo()
                {
                    string storedExt = StaticOpenFileDialog.DefaultExt;
                    StaticOpenFileDialog.DefaultExt = ".dll";
                    StaticOpenFileDialog.ShowDialog();
                    if (StaticOpenFileDialog.FileName.Length > 0)
                    {
                        _fileName = StaticOpenFileDialog.FileName;
                        StaticMainForm._project.ContentAssemblies.AddAssembly(_fileName);

                    }
                    StaticOpenFileDialog.DefaultExt = storedExt;
                }

                public AssemblyInfo(string filename)
                {
                    _fileName = filename;
                    StaticMainForm._project.ContentAssemblies.AddAssembly(_fileName);
                }
            }

            public struct ReplacementInfo
            {
                private string _what;
                private string _with;
                private string _contains;

                [DisplayName("What")]
                [TypeConverter(typeof(ProcessorConverter))]
                public string What
                {
                    get { return _what; }
                    set { _what = value; }
                }

                [DisplayName("With")]
                [TypeConverter(typeof(ProcessorConverter))]
                public string With
                {
                    get { return _with; }
                    set { _with = value; }
                }

                [DisplayName("Contains")]
                public string Contains
                {
                    get { return _contains; }
                    set { _contains = value; }
                }
            }

            private List<AssemblyInfo> _additionalAssemblies;
            private List<ReplacementInfo> _processorReplacer;

            public ProjectPropertiesDesc()
            {
                _additionalAssemblies = new List<AssemblyInfo>();
                _processorReplacer = new List<ReplacementInfo>();
            }

            [Category("Project")]
            [DisplayName("Assemblies")]
            [Description("Additional assemblies")]
            public List<AssemblyInfo> AdditionalAssemblies
            {
                get { return _additionalAssemblies; }
                set { _additionalAssemblies = value; }
            }

            [Category("Project")]
            [DisplayName("Processor replacement")]
            [Description("Define which processor names must be replaced by other")]
            public List<ReplacementInfo> ProcessorReplacer
            {
                get { return _processorReplacer; }
                set { _processorReplacer = value; }
            }
        };

        private ProjectPropertiesDesc _projectProperties = null;

        private void ProjectTreeNodeClicked(object sender, TreeNodeMouseClickEventArgs e)
        {
            contentItemProperties.SelectedObject = e.Node.Tag;
        }

        public mainForm()
        {
            StaticMainForm = this;
            InitializeComponent();
            _project = new ContentProject();
            _projectProperties = new ProjectPropertiesDesc();
            workingDir.Text = "c:\\work\\test_content";
            projectTree.NodeMouseClick += ProjectTreeNodeClicked;

            StaticOpenFileDialog = openFileDialog;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ProcessLog logWindow = new ProcessLog();
            logWindow.Show();
            _project.RegisterLogger(new TextBoxLogger(logWindow.logBox));
            _project.Build(false);
        }

        private void chooseWorkingDir_Click(object sender, EventArgs e)
        {
            folderBrowserDialog.Description = "Choose working dir";
            folderBrowserDialog.ShowDialog();

            if (folderBrowserDialog.SelectedPath.Length < 1)
                return;

            workingDir.Text = folderBrowserDialog.SelectedPath;

            _project.ProjectOptions.IntermediateDirectory = workingDir.Text;
            _project.ProjectOptions.OutputDirectory = workingDir.Text;
            _project.ProjectOptions.RootDirectory = workingDir.Text;

            AddDirectory(workingDir.Text, null);
        }

        private void AddContentFile(string directory, string fileName, TreeNode node)
        {
            foreach (string ext in _acceptableFileFormat)
            {
                if (fileName.ToLower().EndsWith(ext))
                {
                    TreeNode childNode = new TreeNode(fileName.Substring(directory.Length + 1));
                    childNode.Tag = CreateAndCheckContentFile(fileName);
                    node.Nodes.Add(childNode);
                    break;
                }
            }
        }

        private void CheckContentFile(ContentFile file)
        {
            foreach (ProjectPropertiesDesc.ReplacementInfo info in _projectProperties.ProcessorReplacer)
            {
                if (file.Processor == info.What)
                {
                    if (info.Contains != null && info.Contains.Length > 0 && file.FullPath.Contains(info.Contains))
                    {
                        file.Processor = info.With;
                    }
                    break;
                }
            }
        }

        private ContentFile CreateAndCheckContentFile(string filename)
        {
            ContentFile file = _project.InitContentFile(filename);

            CheckContentFile(file);

            return file;
        }

        private void AddDirectory(string directory, TreeNode node)
        {
            string[] files = Directory.GetFiles(directory);
            string[] dirs = Directory.GetDirectories(directory);

            if (node == null)
            {
                node = new TreeNode(directory);
                projectTree.Nodes.Add(node);
            }

            for (int x = 0; x < files.Length; x++)
            {
                if (File.Exists(files[x]))
                {
                    AddContentFile(directory, files[x], node);
                }
            }

            for (int x = 0; x < dirs.Length; x++)
            {
                if (Directory.Exists(dirs[x]))
                {
                    string dirName = dirs[x].Substring(directory.Length);
                    TreeNode dir = new TreeNode(dirName);
                    AddDirectory(dirs[x], dir);
                    node.Nodes.Add(dir);
                }
            }
        }

        private void CreateNewProject()
        {
            PipelineAssemblyManager.ClearAll();
            _project = new ContentProject();
            _projectProperties = new ProjectPropertiesDesc();
            projectTree.Nodes.Clear();
            workingDir.Clear();
            this.Text = "Content Builder - " + _projectName;
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            CreateNewProject();
        }

        private void mainForm_Load(object sender, EventArgs e)
        {
            this.Text = "Content Builder - " + _projectName;
        }

        private void WriteTreeNode(XmlTextWriter writer, TreeNode node)
        {
            writer.WriteStartElement("Node");
            writer.WriteElementString("NodeName", node.Text);
            if (node.Tag != null)
            {
                ContentFile file = node.Tag as ContentFile;
                if (file != null)
                {
                    writer.WriteElementString("FullPath", file.FullPath);
                    writer.WriteElementString("Importer", file.Importer);
                    writer.WriteElementString("OutputName", file.OutputName);
                    writer.WriteElementString("Processor", file.Processor);
                }
            }
            foreach (TreeNode child in node.Nodes)
            {
                WriteTreeNode(writer, child);
            }
            writer.WriteEndElement();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (!_projectName.Contains(".cbproj"))
            {
                saveFileDialog.ShowDialog();
                string fileName = saveFileDialog.FileName;

                if (fileName.Length < 1)
                    return;

                _projectName = fileName;
            }

            XmlTextWriter writer = new XmlTextWriter(_projectName, Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument();

            writer.WriteStartElement("ContentBuilderProject");
            {
                writer.WriteElementString("WorkingDir", workingDir.Text);
                writer.WriteElementString("ProjectName", _projectName);
                writer.WriteElementString("TargetPlatform", _project.ProjectOptions.TargetPlatform);

                writer.WriteStartElement("AdditionalAssemblies");
                foreach (ProjectPropertiesDesc.AssemblyInfo info in _projectProperties.AdditionalAssemblies)
                {
                    writer.WriteElementString("Assembly", info.FileName);
                }
                writer.WriteEndElement();


                writer.WriteStartElement("ProcessorReplacer");
                foreach (ProjectPropertiesDesc.ReplacementInfo info in _projectProperties.ProcessorReplacer)
                {
                    writer.WriteStartElement("Replace");
                    writer.WriteElementString("What", info.What);
                    writer.WriteElementString("With", info.With);
                    writer.WriteElementString("Contains", info.Contains);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();

                writer.WriteStartElement("ProjectTree");
                foreach (TreeNode child in projectTree.Nodes)
                {
                    WriteTreeNode(writer, child);
                }
                writer.WriteEndElement();
            }
            writer.WriteEndDocument();
            this.Text = "Content Builder - " + _projectName;
            writer.Close();
        }

        private void ReadTreeNode(XmlTextReader reader, TreeNode node)
        {
            reader.ReadStartElement();
            node.Text = reader.ReadElementString("NodeName");
            if (node.Text.Contains('\\') || node.Text.Contains('/'))
            {
                TreeNode child = new TreeNode();
                node.Nodes.Add(child);
                ReadTreeNode(reader, child);
            }
            else
            {
                string fullPath = reader.ReadElementString("FullPath");
                ContentFile file = CreateAndCheckContentFile(fullPath);

                string Importer = reader.ReadElementString("Importer");
                file.OutputName = reader.ReadElementString("OutputName");
                string Processor = reader.ReadElementString("Processor");

                node.Tag = file;
            }

            reader.Read();
            if (reader.NodeType == XmlNodeType.Element && reader.Name == "Node")
            {
                if (node.Parent != null)
                {
                    TreeNode child = new TreeNode();
                    node.Parent.Nodes.Add(child);
                    ReadTreeNode(reader, child);
                }
            }
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            openFileDialog.ShowDialog();

            if (openFileDialog.FileName.Length < 1)
                return;

            CreateNewProject();

            XmlTextReader reader = new XmlTextReader(openFileDialog.FileName);
            reader.WhitespaceHandling = WhitespaceHandling.None;

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Document:
                        break;
                    case XmlNodeType.Element:
                        if (reader.Name == "ContentBuilderProject")
                        {
                            reader.Read();
                            workingDir.Text = reader.ReadElementString("WorkingDir");
                            
                            _project.ProjectOptions.IntermediateDirectory = workingDir.Text;
                            _project.ProjectOptions.OutputDirectory = workingDir.Text;
                            _project.ProjectOptions.RootDirectory = workingDir.Text;

                            _projectName = reader.ReadElementString("ProjectName");
                            _project.ProjectOptions.TargetPlatform = reader.ReadElementString("TargetPlatform");

                            reader.ReadStartElement("AdditionalAssemblies");
                            while (reader.NodeType == XmlNodeType.Element && reader.Name == "Assembly")
                            {
                                string filename = reader.ReadElementString("Assembly");
                                ProjectPropertiesDesc.AssemblyInfo info = new ProjectPropertiesDesc.AssemblyInfo(filename);
                                _projectProperties.AdditionalAssemblies.Add(info);
                            }
                            reader.ReadEndElement();

                            reader.ReadStartElement("ProcessorReplacer");
                            while (reader.NodeType == XmlNodeType.Element && reader.Name == "Replace")
                            {
                                ProjectPropertiesDesc.ReplacementInfo info = new ProjectPropertiesDesc.ReplacementInfo();
                                reader.ReadStartElement("Replace");
                                info.What = reader.ReadElementString("What");
                                info.With = reader.ReadElementString("With");
                                info.Contains = reader.ReadElementString("Contains");
                                reader.ReadEndElement();
                                _projectProperties.ProcessorReplacer.Add(info);
                            }
                            reader.ReadEndElement();

                            if (reader.NodeType == XmlNodeType.Element && reader.Name == "ProjectTree")
                            {
                                reader.ReadStartElement();
                                TreeNode node = new TreeNode();
                                projectTree.Nodes.Add(node);
                                ReadTreeNode(reader, node);
                                reader.ReadEndElement();
                            }
                        }
                        break;
                }
            }

            this.Text = "Content Builder - " + _projectName;
        }

        private void btnProperties_Click(object sender, EventArgs e)
        {
            ProjectProperties projProperties = new ProjectProperties();
            projProperties.projProperties.SelectedObject = _projectProperties;
            projProperties.ShowDialog();
        }
    }
}
